﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Data;

namespace Timd.Crm2015.Tools
{
    class Program
    {
        #region Public static methods

        static int Main(string[] args)
        {
            Program p = new Program();

            try
            {
                p.Run();
                return 0;
            }
            catch (Exception)
            {
                return 2;
            }
        }

        #endregion

        #region Private Methods

        private void Run()
        {
            ShowAppPurpose();

            string dataXmlFilePath = PromptForDataXmlFilePath();
            string newFileName = GetNewTextFileName(dataXmlFilePath);

            StringBuilder sb = new StringBuilder();

            string line;
            string crmFieldName;
            string crmFieldValue;

            int recordCounter = 0;

            DataTable dt = BuildDataTable(dataXmlFilePath);
            DataRow dr = null;

            StreamReader sourceFile = new StreamReader(dataXmlFilePath);
            while ((line = sourceFile.ReadLine()) != null)
            {
                line = line.TrimStart(' ');
                
                if (line.StartsWith("<record id"))
                {
                    if (dr != null)
                        dt.Rows.Add(dr);

                    dr = dt.NewRow();
                    recordCounter++;
                    System.Console.WriteLine(recordCounter);
                }
                else if (line.StartsWith("<field "))
                {
                    var xmlText = string.Concat("<Root>", line, "</Root>");
                    var doc = XElement.Parse(xmlText);
                    crmFieldName = doc.Elements("field")
                                    .Attributes("name")
                                    .Select(x => x.Value).FirstOrDefault();

                    crmFieldValue = doc.Elements("field")
                                    .Attributes("value")
                                    .Select(x => x.Value).FirstOrDefault();

                    dr[crmFieldName] = crmFieldValue;
                }

            }

            sourceFile.Close();

            WriteDataTableToTabDelimitedFile(dt, newFileName);

            Console.WriteLine("\n\nProcess complete.");

            Console.ReadKey();
        }

        private DataTable BuildDataTable(string dataXmlFilePath)
        {
            string line;
            string crmFieldName;

            DataTable dt = new DataTable("data");
            List <string> fields = new List<string>();

            StreamReader sourceFile = new StreamReader(dataXmlFilePath);
            while ((line = sourceFile.ReadLine()) != null)
            {
                line = line.TrimStart(' ');

                if (line.StartsWith("<field "))
                {
                    var xmlText = string.Concat("<Root>", line, "</Root>");
                    var doc = XElement.Parse(xmlText);
                    crmFieldName = doc.Elements("field")
                                    .Attributes("name")
                                    .Select(x => x.Value).FirstOrDefault();

                    if (!fields.Contains(crmFieldName))
                    {
                        fields.Add(crmFieldName);
                    }
                }
            }

            sourceFile.Close();

            foreach (string field in fields)
            {
                dt.Columns.Add(new DataColumn(field, typeof(string)));
            }

            return dt;
        }

        private void WriteDataTableToTabDelimitedFile(DataTable dt, string filename)
        {
            string delimiter = "\t";
            if (File.Exists(filename))
            {
                File.Delete(filename);
            }
            using (StreamWriter sr = new StreamWriter(filename))
            {
                StringBuilder builder = new StringBuilder();

                foreach (DataColumn dc in dt.Columns)
                {
                    builder.Append(delimiter).Append(dc.ColumnName);
                }

                sr.WriteLine(builder.ToString());

                string colValue;

                foreach (DataRow dr in dt.Rows)
                {
                    builder = new StringBuilder();

                    foreach (DataColumn dc in dt.Columns)
                    {
                        colValue = CleanString(dr[dc.ColumnName].ToString());
                        builder.Append(delimiter).Append(colValue);
                    }

                    sr.WriteLine(builder.ToString());
                }
            }
        }

        private string CleanString(string value)
        {
            return value.Replace("\n", "").Replace("\r", "").Replace("\t", " ");
        }

        private void ShowAppPurpose()
        {
            Console.WriteLine("This application transforms data.xml (exported with the CRM 2013");
            Console.WriteLine("Configuration Migration Tool) into a format that can be imported");
            Console.WriteLine("into Excel.");
        }

        private string PromptForDataXmlFilePath()
        {
            Console.Write("\n\nEnter full path to data.xml file: ");
            string dataXmlFilePath = Console.ReadLine().Replace("\"", "");
            return dataXmlFilePath;
        }

        private string GetNewTextFileName(string sourceDataXmlFilePath)
        {
            return sourceDataXmlFilePath.Replace(".xml", ".txt");
        }

        #endregion
    }
}
